package top.songxs.gmall.order.biz.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import top.songxs.gmall.cart.entity.CartItem;
import top.songxs.gmall.cart.vo.UserAuthInfoVo;
import top.songxs.gmall.common.execption.GmallException;
import top.songxs.gmall.common.util.UserAuthUtil;
import top.songxs.gmall.feign.cart.CartRpcFeignClient;
import top.songxs.gmall.feign.user.UserFeignClient;
import top.songxs.gmall.feign.ware.WareManageFeignClient;
import top.songxs.gmall.order.biz.OrderBizService;
import top.songxs.gmall.order.entity.OrderDetail;
import top.songxs.gmall.order.entity.OrderInfo;
import top.songxs.gmall.order.entity.PaymentInfo;
import top.songxs.gmall.order.enums.OrderStatus;
import top.songxs.gmall.order.enums.ProcessStatus;
import top.songxs.gmall.order.mapper.OrderInfoMapper;
import top.songxs.gmall.order.mapper.PaymentInfoMapper;
import top.songxs.gmall.order.service.OrderDetailService;
import top.songxs.gmall.order.vo.DetailVo;
import top.songxs.gmall.order.vo.OrderConfirmVo;
import top.songxs.gmall.rabbit.constant.MqConstant;
import top.songxs.gmall.user.entity.UserAddress;
import top.songxs.gmall.ware.entity.Sku;
import top.songxs.gmall.ware.entity.WareStockMsg;
import top.songxs.gmall.ware.vo.WareSkuMapVo;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderBizServiceImpl implements OrderBizService {

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private CartRpcFeignClient cartRpcFeignClient;

    @Autowired
    private WareManageFeignClient wareManageFeignClient;

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private PaymentInfoMapper paymentInfoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderDetailService orderDetailService;

    @Override
    public OrderConfirmVo orderConfirmData() {
        // 远程调用购物车服务接口，获取购物车相关数据，构建OrderConfirmVo对象进行返回

        // 创建OrderConfirmVo封装响应结果数据
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//获取request，往异步线程中添加，实现异步编排
        //开启一个异步任务
        CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //获取购物车中所有物品项
            List<CartItem> cartItemList = cartRpcFeignClient.findAllCheckedCartItem().getData();
            List<DetailVo> detailVoList = cartItemList.stream().map(cartItem -> {
                DetailVo detailVo = new DetailVo();
                detailVo.setImgUrl(cartItem.getImgUrl());
                detailVo.setSkuName(cartItem.getSkuName());
                detailVo.setOrderPrice(cartItem.getSkuPrice());
                detailVo.setSkuNum(cartItem.getSkuNum());
                detailVo.setSkuId(cartItem.getSkuId());
                HashMap<String, String> hashMap = new HashMap<>();
                hashMap.put("num", cartItem.getSkuNum() + "");
                hashMap.put("skuId", cartItem.getSkuId() + "");
                //        String numstr = (String) hashMap.get("num");
                //        Integer num=Integer.parseInt(numstr);
                //        String skuid =(String)hashMap.get("skuId");
                //        boolean hasStock = gwareService.hasStockBySkuId( skuid , num);
                //远程调用一下库存系统
                ResponseEntity<String> result = wareManageFeignClient.hasStock(hashMap);
                String s = result.getBody();
                detailVo.setHasStock(s);
                return detailVo;
            }).collect(Collectors.toList());
            //获取购物车中物品总数量
            Integer skuNumCount = detailVoList
                    .stream()
                    .map(detailVo -> detailVo.getSkuNum())
                    .reduce(Integer::sum)
                    .get();
            //获取所有商品的总价格
            BigDecimal totalAmount = detailVoList
                    .stream()
                    .map(detailVo -> detailVo.getOrderPrice().multiply(new BigDecimal(detailVo.getSkuNum())))
                    .reduce(BigDecimal::add)
                    .get();
            orderConfirmVo.setDetailArrayList(detailVoList);
            orderConfirmVo.setTotalNum(skuNumCount);
            orderConfirmVo.setTotalAmount(totalAmount);
        });
        //开启一个异步任务
        CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //远程调用用户微服务，查询所有的用户地址
            List<UserAddress> userAddressList = userFeignClient.getUserAllAddress().getData();
            orderConfirmVo.setUserAddressList(userAddressList);
        });
        CompletableFuture<Void> cf3 = CompletableFuture.runAsync(() -> {
            // 随机生成一个外部单号
            String uuid = IdUtil.fastSimpleUUID();
            //并把它存到redis中去，后续校验使用
            //.opsForValue().set("order:confirm:" + uuid, "x", 30, TimeUnit.MILLISECONDS);
            redisTemplate.opsForValue().set("order:confirm:" + uuid, "x", 30L, TimeUnit.MINUTES);
            orderConfirmVo.setTradeNo(uuid);
        });

        CompletableFuture.allOf(cf1, cf2, cf3).join();

        return orderConfirmVo;
    }

    @Override
    public OrderInfo findById(Long orderId) {
        UserAuthInfoVo userAuthInfo = UserAuthUtil.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId, orderId);
        wrapper.eq(OrderInfo::getUserId, userId);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        return orderInfo;
    }


    //更改订单状态，并保存到payment_info中
    @Override
    public void payedUpdateOrderStatus(Map<String, String> params) {
        //根据参数，构建一个paymentInfo对象
        PaymentInfo paymentInfo = buildPaymentInfo(params);
        // 保存支付信息数据
        try {
            paymentInfoMapper.insert(paymentInfo);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        // 修改支付状态：如果支付的状态是未支付，或者已关闭那么此时将支付状态改为已支付
        this.updateOrderStatus(paymentInfo);
        //支付状态修改完毕以后发送扣减库存消息
        WareStockMsg wareStockMsg = this.buildWareStockMsg(paymentInfo);
        rabbitTemplate.convertAndSend(MqConstant.EXCHANGE_DIRECT_WARE_STOCK, MqConstant.ROUTING_WARE_STOCK, JSON.toJSONString(wareStockMsg));
    }

    @Override
    public void updateOrderStatusToWaitingShipment(Map<String, String> map) {
        String orderId = map.get("orderId");
        String status = map.get("status");
        if (MqConstant.DEDUCTED.equals(status)) {
            //正常出库，没有存在超卖现象，修改订单状态为待发货状态
            OrderInfo orderInfo = this.orderInfoMapper.selectById(orderId);
            //订单状态
            String orderStatus = orderInfo.getOrderStatus();
            //订单处理状态
            String processStatus = orderInfo.getProcessStatus();
            if (OrderStatus.PAID.name().equals(orderStatus) && ProcessStatus.PAID.name().equals(processStatus)) {
                orderInfo.setProcessStatus(ProcessStatus.WAITING_DELEVER.name());
                orderInfo.setOrderStatus(OrderStatus.WAITING_DELEVER.name());
                LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(OrderInfo::getId, orderId);
                wrapper.eq(OrderInfo::getOrderStatus, orderStatus);
                wrapper.eq(OrderInfo::getProcessStatus, processStatus);
                orderInfoMapper.update(orderInfo, wrapper);
            } else {
                //后续处理，存在超卖就退款业务
                throw new GmallException("订单超卖,后续走退款", 1128);
            }

        }
    }

    //拆单
    @Override
    public List<WareStockMsg> orderSpilt(Long orderId, String wareSkuMapJson) {

        // 1、解析库存和skuId对应请求的json数据
        // [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        List<WareSkuMapVo> wareSkuMapVoList = JSON.parseArray(wareSkuMapJson, WareSkuMapVo.class);
        // 2、查询订单数据
        OrderInfo parentOrderInfo = orderInfoMapper.selectById(orderId);

        // 创建一个List集合，存储拆单消息数据,按照商品仓库进行拆单，一个wareId就是一个新的订单。
        List<WareStockMsg> wareStockMsgList = new ArrayList<>();
        for (WareSkuMapVo wareSkuMapVo : wareSkuMapVoList) {
            OrderInfo info = new OrderInfo();
            info.setConsignee(parentOrderInfo.getConsignee());
            info.setConsigneeTel(parentOrderInfo.getConsigneeTel());


            List<Long> skuIds = wareSkuMapVo.getSkuIds();
            LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OrderDetail::getOrderId, orderId);
            wrapper.in(OrderDetail::getSkuId, skuIds);
            List<OrderDetail> orderDetailList = orderDetailService.list(wrapper);

            BigDecimal totalAmount = orderDetailList.stream()
                    .map(orderDetail -> orderDetail.getOrderPrice()
                            .multiply(new BigDecimal(orderDetail.getSkuNum())))
                    .reduce(BigDecimal::add)
                    .get();


            info.setTotalAmount(totalAmount);
            info.setOrderStatus(parentOrderInfo.getOrderStatus());
            info.setUserId(parentOrderInfo.getUserId());
            info.setPaymentWay(parentOrderInfo.getPaymentWay());
            info.setDeliveryAddress(parentOrderInfo.getDeliveryAddress());
            info.setOrderComment(parentOrderInfo.getOrderComment());
            info.setOutTradeNo(parentOrderInfo.getOutTradeNo());

            info.setTradeBody(orderDetailList.get(0).getSkuName());
            info.setCreateTime(new Date());
            info.setExpireTime(parentOrderInfo.getExpireTime());
            info.setProcessStatus(parentOrderInfo.getProcessStatus());
            info.setTrackingNo(parentOrderInfo.getTrackingNo());
            info.setParentOrderId(parentOrderInfo.getId());
            info.setImgUrl(orderDetailList.get(0).getImgUrl());

            info.setProvinceId(0L);
            info.setOperateTime(new Date());
            info.setActivityReduceAmount(new BigDecimal("0"));
            info.setCouponAmount(new BigDecimal("0"));
            info.setOriginalTotalAmount(totalAmount);
            info.setFeightFee(new BigDecimal("0"));
            info.setRefundableTime(new Date());
            //子订单进行保存
            orderInfoMapper.insert(info);
            //保存订单明细
            List<OrderDetail> details = orderDetailList.stream().map(orderDetail -> {
                OrderDetail newOrderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetail,newOrderDetail);
                newOrderDetail.setId(null);
                newOrderDetail.setOrderId(info.getId());

                return newOrderDetail;
            }).collect(Collectors.toList());

            orderDetailService.saveBatch(details);
            // 构建WareStockMsg消息数据
            WareStockMsg wareStockMsg = new WareStockMsg();
            wareStockMsg.setOrderId(info.getId());
            wareStockMsg.setConsignee(info.getConsignee());
            wareStockMsg.setConsigneeTel(info.getConsigneeTel());
            wareStockMsg.setOrderComment(info.getOrderComment());
            wareStockMsg.setOrderBody(info.getTradeBody());
            wareStockMsg.setDeliveryAddress(info.getDeliveryAddress());


            List<Sku> skus = details.stream().map(orderDetail -> {
                Sku sku = new Sku();
                sku.setSkuId(orderDetail.getSkuId());
                sku.setSkuNum(orderDetail.getSkuNum());
                sku.setSkuName(orderDetail.getSkuName());
                return sku;
            }).collect(Collectors.toList());
            wareStockMsg.setDetails(skus);
            wareStockMsg.setWareId(wareSkuMapVo.getWareId());
            wareStockMsgList.add(wareStockMsg);
        }
        //修改老订单的状态变成已拆单状态
            parentOrderInfo.setOrderStatus(OrderStatus.SPLIT.name());
            parentOrderInfo.setProcessStatus(ProcessStatus.SPLIT.name());
            orderInfoMapper.updateById(parentOrderInfo);
        return wareStockMsgList;
    }

    private WareStockMsg buildWareStockMsg(PaymentInfo paymentInfo) {
        WareStockMsg wareStockMsg = new WareStockMsg();
        wareStockMsg.setOrderId(Long.parseLong(paymentInfo.getOrderId()));
        OrderInfo orderInfo = orderInfoMapper.selectById(Long.parseLong(paymentInfo.getOrderId()));
        //根据orderId查一次orderInfo
        wareStockMsg.setConsignee(orderInfo.getConsignee());
        wareStockMsg.setConsigneeTel(orderInfo.getConsigneeTel());
        wareStockMsg.setOrderComment(orderInfo.getOrderComment());
        wareStockMsg.setOrderBody(orderInfo.getTradeBody());
        wareStockMsg.setDeliveryAddress(orderInfo.getDeliveryAddress());
//        wareStockMsg.setPaymentWay(orderInfo.getPaymentWay());  //写死默认就是2
        //构建一个Details
        List<Sku> lists = this.buildDetails(orderInfo.getId());
        wareStockMsg.setDetails(lists);
        return wareStockMsg;
    }

    private List<Sku> buildDetails(Long orderId) {
        LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderDetail::getOrderId, orderId);
        List<OrderDetail> orderDetailList = orderDetailService.list(wrapper);
        List<Sku> skus = orderDetailList.stream().map(orderDetail -> {
            Sku sku = new Sku();
            sku.setSkuId(orderDetail.getSkuId());
            sku.setSkuNum(orderDetail.getSkuNum());
            sku.setSkuName(orderDetail.getSkuName());
            return sku;

        }).collect(Collectors.toList());

        return skus;
    }

    //把订单的支付状态设置为已支付状态
    private void updateOrderStatus(PaymentInfo paymentInfo) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId, paymentInfo.getOrderId());
        wrapper.eq(OrderInfo::getUserId, paymentInfo.getUserId());
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        //判断订单状态是否是未支付状态，或者已关闭，是的话改为已支付，
        if ((OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus()) || OrderStatus.CLOSED.name().equals(orderInfo.getOrderStatus())) &&
                (ProcessStatus.UNPAID.name().equals(orderInfo.getProcessStatus()) || ProcessStatus.CLOSED.name().equals(orderInfo.getProcessStatus()))
        ) {
            //修改订单状态
            orderInfo.setOrderStatus(OrderStatus.PAID.name());
            orderInfo.setProcessStatus(ProcessStatus.PAID.name());
            //使用cas自旋逻辑，乐观锁
            wrapper.in(OrderInfo::getOrderStatus, OrderStatus.UNPAID.name(), OrderStatus.CLOSED.name());
            wrapper.in(OrderInfo::getProcessStatus, ProcessStatus.UNPAID.name(), ProcessStatus.CLOSED.name());
            //执行修改操作
            orderInfoMapper.update(orderInfo, wrapper);
        }
    }


    //构建支付信息
    private PaymentInfo buildPaymentInfo(Map<String, String> params) {
        //拿着外部交易号，直接去查order info信息
        String outTradeNo = params.get("out_trade_no");
        String tradeNo = params.get("trade_no");
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getOutTradeNo, outTradeNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setUserId(orderInfo.getUserId());
        paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
        paymentInfo.setOrderId(orderInfo.getId() + "");
        paymentInfo.setPaymentType("Alipay");
        paymentInfo.setTradeNo(tradeNo);
        paymentInfo.setTotalAmount(orderInfo.getTotalAmount());
        paymentInfo.setSubject(orderInfo.getTradeBody());
        paymentInfo.setPaymentStatus(OrderStatus.PAID.name());
        paymentInfo.setCreateTime(orderInfo.getCreateTime());
        paymentInfo.setCallbackTime(new Date());
        paymentInfo.setCallbackContent(JSON.toJSONString(params));
        return paymentInfo;
    }


}
